"""
Author: runyu.ma

ast_walker.py
"""

from ..core.dslc_parser import ASTNode, BinaryOp, UnaryOp, BlockOp, Identifier
from ..core.dslc_symbol_table import SymbolTable
from typing import Callable

def traversal_ast_to(stab: SymbolTable, ast: ASTNode, fliter: Callable[[SymbolTable, ASTNode], bool], processor: Callable[[SymbolTable, ASTNode], ASTNode]):
    '''
    遍历ast并执行
    '''
    ast = __proc_now(stab, ast, fliter, processor)
    return ast


def __proc_now(stab: SymbolTable, ast: ASTNode, fliter: Callable[[SymbolTable, ASTNode], bool],\
    processor: Callable[[SymbolTable, ASTNode], ASTNode]):
    '''遍历ast'''
    #优先替换上层，这样可以将nested的逻辑交给processor处理
    if fliter(stab, ast):
        ast = processor(stab, ast)
    if isinstance(ast, UnaryOp):
        ast.x = __proc_now(stab, ast.x, fliter, processor)
    if isinstance(ast, BinaryOp):
        ast.l = __proc_now(stab, ast.l, fliter, processor)
        ast.r = __proc_now(stab, ast.r, fliter, processor)
    if isinstance(ast, BlockOp):
        oplistn = []
        sdeepth = 0
        for it in ast.oplist:
            #
            if isinstance(it, UnaryOp) and it.op == ':':
                if isinstance(it.x, Identifier):
                    stab.enter_scope(it.x.name)
                elif isinstance(it.x, BinaryOp):
                    stab.enter_scope(it.x.l.name+"::"+it.x.r.value)
                else:
                    raise ValueError('can not parse COLON UnaryOp')
                sdeepth = sdeepth + 1
            #
            oplistn.append(__proc_now(stab, it, fliter, processor))
        ast.oplist = oplistn
        #
        for _ in range(sdeepth):
            stab.exit_scope()
    return ast



